module aru_arb_wrgen_cfg_pipe (
    input logic                              clk,
    input logic                              rst_n,
          aru_arb_wrgen_cfg_if.in            u_aru_cfg_if,
          aru_arb_wrgen_cfg_if.crd_gen_out   u_aru_crd_gen_cfg_if,
          aru_arb_wrgen_cfg_if.addr_calc_out u_aru_addr_calc_cfg_if
);

    // Configuration pipeline depth
    localparam CFG_PIPE_DEPTH = 2;

    // Configuration index counter (to receive)
    logic [$clog2(CFG_PIPE_DEPTH)-1:0] cfg_idx_to_recv;
    always_ff @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            cfg_idx_to_recv <= 'd0;
        end else begin
            if (u_aru_cfg_if.vld && u_aru_cfg_if.rdy) begin
                cfg_idx_to_recv <= cfg_idx_to_recv + 'd1;
            end
        end
    end

    // Configuration storage
    typedef struct packed {
        arb_addr_t arb_addr;
        idx_t      slice_m;
        idx_t      slice_n;
        logic      reduce_m;
        logic      reduce_n;
        idx_t      instr_idx;
    } cfg_t;

    cfg_t cfg_slt[CFG_PIPE_DEPTH];
    logic cfg_vld[CFG_PIPE_DEPTH];
    logic [1:0] cfg_sent[CFG_PIPE_DEPTH];  // [0]: crd_gen sent, [1]: addr_calc sent

    // Configuration send indices
    logic [$clog2(CFG_PIPE_DEPTH)-1:0] cfg_idx_to_send_crd_gen;
    logic [$clog2(CFG_PIPE_DEPTH)-1:0] cfg_idx_to_send_addr_calc;

    // Handle receive (load), send (mark sent + advance indices), and clear when both sent
    always_ff @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            for (integer i = 0; i < CFG_PIPE_DEPTH; i = i + 1) begin
                cfg_vld[i]  <= 1'b0;
                cfg_slt[i]  <= 'd0;
                cfg_sent[i] <= 2'b00;
            end
            cfg_idx_to_send_crd_gen   <= 'd0;
            cfg_idx_to_send_addr_calc <= 'd0;
        end else begin
            // Loop over pipeline slots
            for (integer i = 0; i < CFG_PIPE_DEPTH; i = i + 1) begin
                // By default keep values
                cfg_slt[i]  <= cfg_slt[i];
                cfg_vld[i]  <= cfg_vld[i];
                cfg_sent[i] <= cfg_sent[i];

                // 1) If slot empty, possibly load new config
                if (cfg_vld[i] == 1'b0) begin
                    if (u_aru_cfg_if.vld && u_aru_cfg_if.rdy && (i == cfg_idx_to_recv)) begin
                        cfg_vld[i]           <= 1'b1;
                        cfg_sent[i]          <= 'd0;
                        cfg_slt[i].arb_addr  <= u_aru_cfg_if.arb_addr;
                        cfg_slt[i].slice_m   <= u_aru_cfg_if.slice_m;
                        cfg_slt[i].slice_n   <= u_aru_cfg_if.slice_n;
                        cfg_slt[i].reduce_m  <= u_aru_cfg_if.reduce_m;
                        cfg_slt[i].reduce_n  <= u_aru_cfg_if.reduce_n;
                        cfg_slt[i].instr_idx <= u_aru_cfg_if.instr_idx;
                    end
                end else begin
                    // 2) Clear slot if both sent
                    if (cfg_sent[i] == 2'b11) begin
                        cfg_vld[i] <= 1'b0;
                    end
                end
            end

            // 3) Handle send-to-crd_gen
            if (u_aru_crd_gen_cfg_if.rdy) begin
                if (cfg_vld[cfg_idx_to_send_crd_gen] && (cfg_sent[cfg_idx_to_send_crd_gen][0] == 1'b0)) begin
                    cfg_sent[cfg_idx_to_send_crd_gen][0] <= 1'b1;
                    cfg_idx_to_send_crd_gen              <= cfg_idx_to_send_crd_gen + 'd1;
                end
            end

            // 4) Handle send-to-addr_calc
            if (u_aru_addr_calc_cfg_if.rdy) begin
                if (cfg_vld[cfg_idx_to_send_addr_calc] && (cfg_sent[cfg_idx_to_send_addr_calc][1] == 1'b0)) begin
                    cfg_sent[cfg_idx_to_send_addr_calc][1] <= 1'b1;
                    cfg_idx_to_send_addr_calc              <= cfg_idx_to_send_addr_calc + 'd1;
                end
            end
        end
    end

    // Input interface backpressure
    assign u_aru_cfg_if.rdy = ~cfg_vld[cfg_idx_to_recv];

    // Output assignments for crd_gen
    assign u_aru_crd_gen_cfg_if.vld         = cfg_vld[cfg_idx_to_send_crd_gen] &&
                                             (cfg_sent[cfg_idx_to_send_crd_gen][0] == 1'b0);
    assign u_aru_crd_gen_cfg_if.slice_m = cfg_slt[cfg_idx_to_send_crd_gen].slice_m;
    assign u_aru_crd_gen_cfg_if.slice_n = cfg_slt[cfg_idx_to_send_crd_gen].slice_n;
    assign u_aru_crd_gen_cfg_if.reduce_m = cfg_slt[cfg_idx_to_send_crd_gen].reduce_m;
    assign u_aru_crd_gen_cfg_if.reduce_n = cfg_slt[cfg_idx_to_send_crd_gen].reduce_n;

    // Output assignments for addr_calc
    assign u_aru_addr_calc_cfg_if.vld         = cfg_vld[cfg_idx_to_send_addr_calc] &&
                                               (cfg_sent[cfg_idx_to_send_addr_calc][1] == 1'b0);
    assign u_aru_addr_calc_cfg_if.arb_addr = cfg_slt[cfg_idx_to_send_addr_calc].arb_addr;
    assign u_aru_addr_calc_cfg_if.slice_m = cfg_slt[cfg_idx_to_send_addr_calc].slice_m;
    assign u_aru_addr_calc_cfg_if.slice_n = cfg_slt[cfg_idx_to_send_addr_calc].slice_n;
    assign u_aru_addr_calc_cfg_if.reduce_m = cfg_slt[cfg_idx_to_send_addr_calc].reduce_m;
    assign u_aru_addr_calc_cfg_if.reduce_n = cfg_slt[cfg_idx_to_send_addr_calc].reduce_n;
    assign u_aru_addr_calc_cfg_if.instr_idx = cfg_slt[cfg_idx_to_send_addr_calc].instr_idx;

endmodule
